<?php
namespace bee;
/*
 * @author dy
 */
class XMLDataHub extends \DOMDocument implements Isingleton
{ protected static      $__instance;
  private             $form;				// root
  private             $rowData;			// reci tablice
  private             $arrays;			// šifre
  private             $tables;			// tablice
  private             $variables;		// varijable
  private             $widgets;     // kontrole forme
  private             $jqueries;     // javascript kontrole forme
  private             $others;       // ostali podaci  i objekti

  /**
   *
   * @param unknown_type $ver
   * @param unknown_type $encoding
   * @return XMLDataHub
   */
  public static function getInstance($ver = "1.0", $encoding = "UTF-8")
  { if(!static::$__instance)
    { static::$__instance = new static();
    }
    //echo "kn";
  	return static::$__instance;
  }

  private function __clone()
  {;
  }

  /**
   *
   * @param unknown_type $ver
   * @param unknown_type $encoding
   * @return DOMSQLDocument
   */
  public  function __construct($ver = "1.0", $encoding = "UTF-8")
  {
    if(static::$__instance)
  	{ throw new \Exception("Singleton creation problem in file: " . __FILE__ . " line: " . __LINE__);
    }
    static::$__instance = $this;
  	parent::__construct($ver, $encoding);
//echo "k+";
    $cNode = self::createComment("&scaron;");
    $this->appendChild($cNode);
  	$this->form = self::createElement("form");
  	self::appendChild($this->form);
  	$this->rowData = self::createElement("rowData");
  	$this->form->appendChild($this->rowData);
  	$this->tables = self::createElement("tables");
  	$this->form->appendChild($this->tables);
  	$this->arrays = self::createElement("arrays");
  	$this->form->appendChild($this->arrays);
  	$this->variables = self::createElement("variables");
  	$this->form->appendChild($this->variables);
  	$this->widgets = self::createElement("widgets");
    $this->form->appendChild($this->widgets);
    $this->others = self::createElement("others");
    $this->form->appendChild($this->others);
    $this->jqueries = self::createElement("jqueries");
    $this->form->appendChild($this->jqueries);
    $this->jqueries->appendChild(self::createElement("datePickers"));
    $this->jqueries->appendChild(self::createElement("autoCompleters"));
    //print_r($this);
  }

  /**
   * Enter description here ...
   * @param string $fragmentPath
   * @param string $fragmentString
   */
  public function appendFragment($fragmentPath, $fragmentString, $overwrite = true)
  {
    $fragment = $this->createDocumentFragment();
    $fragment->appendXML($fragmentString);

    $xpath = new \DOMXPath($this);
    /*
    if($overwrite)
    { $removeNodes = $xpath->query($fragmentPath);
      if($removeNodes->length > 0)
      { $ukl = $removeNodes->item(0)->parentNode->removeChild($removeNodes->item(0));
      }
    }
    */
    $insertNode = $xpath->query($fragmentPath);
    if($insertNode->length > 0)
    { $insertNode->item(0)->appendChild($fragment);
      //echo "<br />$nodeValue";
    } else
    { return false;
    }
  }

  /**
   *
   * @param \DOMElement $parentDOMNode
   * @param $nodeName
   * @param $nodeValue
   * @param $overwrite overwrite existing node
   *
   * dodavanje novog čvora u DOM stablo
   *
   */
  private function setDOMNode(\DOMElement $parentDOMNode, $nodeName, $nodeValue, $overwrite = true)
  {
    try
    {
      $DOMNodeElement = $this->createElement($nodeName);
      $DOMNodeElement = $parentDOMNode->appendChild($DOMNodeElement);
      if(is_object($nodeValue))
      { foreach ($nodeValue as $oKey => $oVal)
        { //echo "<br />:+: $oKey, $oVal:+:";
          self::setDOMNode($DOMNodeElement, $oKey, $oVal, $overwrite);
        }
      } else if(is_array($nodeValue))
      { foreach ($nodeValue as $key => $val)
        { $DOMNodeArrValue = self::setDOMNode($DOMNodeElement, "value", $val, $overwrite);
          $DOMNodeArrValue->setAttributeNode(new \DOMAttr("key", $key));//appendChild($DOMkey);
        }
      } else if(is_string($nodeValue) || is_numeric($nodeValue) || is_bool($nodeValue))
      { $textValue = self::createTextNode($nodeValue);
        $DOMNodeElement->appendChild($textValue);

      } else
      {/* echo " ** $nodeName ** " ;
        var_dump($nodeValue);
        echo "<br />";  */
      }
    } catch(Exception $e)
    { echo( "--" - $nodeName . "(xmldatahub setdomnode exception)/" . print_r($e->getCode(), true));
    }
    return $DOMNodeElement;
  }

	/**
	 *
	 * @param unknown_type $nodePath
	 * @param unknown_type $nodeName
	 * @param unknown_type $nodeValue
	 * @param unknown_type $overwrite
	 *
	 */
  public function setNode($nodePath, $nodeName, $nodeValue, $overwrite = true)
  { try
    {
      $xpath = new \DOMXPath($this);
      if($overwrite)
      { $removeNodes = $xpath->query($nodePath . "/" . $nodeName);
        if($removeNodes->length > 0)
        { $ukl = $removeNodes->item(0)->parentNode->removeChild($removeNodes->item(0));
        }
      }
      $insertNode = $xpath->query($nodePath);
      if($insertNode->length == 0)
      { $insertNode = $this->createPath($nodePath);
        //echo "\n<br />+" . $insertNode->nodeName;
      } else
      { $insertNode = $insertNode->item(0);
        //echo "\n<br /> " . $insertNode->nodeName;
      }
      $insertNode = $this->setDOMNode($insertNode, $nodeName, $nodeValue, $overwrite);
        //echo "<br />$nodeValue";
    } catch(Exception $e)
    { echo( "--" - $nodeName . "(xmldatahub setnode exception)/" . print_r($e->getCode(), true));
    }

    return $insertNode;
  }

  private function createPath($nodePath)
  { $xpath = new \DOMXPath($this);
    $builtPath = "";
    while($nodePath)
    { $pos = strpos($nodePath, "/");
      if($pos !== false)
      { $nodeName = substr($nodePath, 0, $pos);
        $nodePath = substr($nodePath, strpos($nodePath, "/") + 1);
      } else
      { $nodeName = $nodePath;
        $nodePath = "";
      }
      $builtPath .=  ($nodeName ? "/" . $nodeName : "");
      //echo "<br />$br Node path: $builtPath - $nodeName - $nodePath";
      if($builtPath)
      { $DOMnodes = $xpath->query($builtPath);
        if($DOMnodes->length > 0)
        { $actualDOMnode = $DOMnodes->item(0);
        } else
        { $newNode = $this->createElement($nodeName);
          $actualDOMnode = $actualDOMnode->appendChild($newNode);
        }
      }
      //if($br++ > 100) break;
    }
    return $actualDOMnode;
  }//

  public function setNode_old($nodePath, $nodeName, $nodeValue, $overwrite = true)
  {
    $xpath = new \DOMXPath($this);
    if($overwrite)
    {
      $removeNodes = $xpath->query($nodePath . "/" . $nodeName);
      if($removeNodes->length > 0)
      {
        $ukl = $removeNodes->item(0)->parentNode->removeChild($removeNodes->item(0));
        //var_dump($ukl);
      }
    }
    $insertNode = $xpath->query($nodePath);
    if($insertNode->length > 0)
    {
      $insertNode = $this->setDOMNode($insertNode->item(0), $nodeName, $nodeValue, $overwrite);
      //echo "<br />$nodeValue";
    }
    return $insertNode;
  }



  public function setRow(DAO $DAO, $row_name = "", $overwrite = true)
  { $row = $this->setNode("/form/rowData",$row_name ? $row_name : str_replace("\\", "_", get_class($DAO)), $DAO, $overwrite);
    return $this->saveXML($row);
    return $row;
  }

  public function setArray(array $array = null, $arr_name, $overwrite = true)
  { try
    {//die("$arr_name:" . print_r($array, true));
      $arr = $this->setNode("/form/arrays", $arr_name, $array, $overwrite);

    } catch(Exception $e)
    { echo( "--" - $nodeName . "(xmldatahub setarray exception)/" . print_r($e->getCode(), true));
    }
    return $this->saveXML($arr);
    //return $arr;
  }

  public function setTable(rowSet $rowSet, $table_name = "", array &$foreignKeys = null, $overwrite = true)
  {
    if($overwrite)
    { $xpath = new \DOMXPath($this);
      $removeNodes = $xpath->query("/form/tables/" . ($table_name ?: $rowSet->getTableName()));
      if($removeNodes->length > 0)
      { $ukl = $removeNodes->item(0)->parentNode->removeChild($removeNodes->item(0));
        //var_dump($ukl);
      }
    }

    $table = self::createElement($table_name ?: $rowSet->getTableName());
  	//$this->tables->appendChild($table);
  	$DAOrow = clone $rowSet->getDAORow();
  	while($rowSet->getRow($DAOrow))
  	{
  	  $row = self::createElement("row");
  	  $table->appendChild($row);
  	  foreach ($DAOrow as $key => $value)
      {	if(!is_array($value))
        { $DAOfield = self::createElement($key);
          $row->appendChild($DAOfield);
          if(isset($foreignKeys[$key]))
          {	$XMLvalue = self::createTextNode(isset($foreignKeys[$key][$value]) ? $foreignKeys[$key][$value] : "*");
          } else
          { $XMLvalue = self::createTextNode($value);
          }
    	  $DAOfield->appendChild($XMLvalue);
    	}
  	  }
  	  //echo print_r($DAOrow, true) . "<br /><br />";
  	}
  	$this->tables->appendChild($table);
  	return $this->saveXML($table);
  }

  public function setTable2(rowSet $rowSet, $table_name = "", array $callBacks, $overwrite = true)
  {	//$callBacksClone = $callBacks;
    if($overwrite)
    { $xpath = new \DOMXPath($this);
      $removeNodes = $xpath->query("/form/tables/" . ($table_name ?: $rowSet->getTableName()));
      if($removeNodes->length > 0)
      { $ukl = $removeNodes->item(0)->parentNode->removeChild($removeNodes->item(0));
        //var_dump($ukl);
      }
    }
    $table = self::createElement($table_name ?: $rowSet->getTableName());
  	$this->tables->appendChild($table);
  	$DAOrow = clone $rowSet->getDAORow();
  	while($rowSet->getRow($DAOrow))
  	{ $callBacksClone = $callBacks;
  	  $row = self::createElement("row");
  	  $table->appendChild($row);
  	  foreach ($DAOrow as $key => $value)
  	  { $DAOfield = self::createElement($key);
    		if(array_key_exists($key, $callBacksClone))
    		{ //echo "<br /><br />KEY $key: $value";
    		  foreach ($callBacksClone[$key]["params"] as $pkey => &$pvalue)
    		  { if($pvalue == "__field__")
    			{ $pvalue = $value;
    			  //echo "<br />PVALUE: $pvalue";
    			}
    		  }
    		  $value = call_user_func_array($callBacksClone[$key]["function"], $callBacksClone[$key]["params"]);
    		}
    		$row->appendChild($DAOfield);
    		if(!is_array($value))
    		{ $DAOvalue = self::createTextNode($value);
    		  $DAOfield->appendChild($DAOvalue);
    		}
  	  }
  	}
  	return $this->saveXML($table);
  }

  public function setVariable($varName, $varValue = "", $overwrite = true)
  {	$var = $this->setNode( "/form/variables", $varName, $varValue, $overwrite);
    return $this->saveXML($var);
  }

  public function setPath($path, $value = "", $overwrite = true)
  { $nodeName = substr($path, strrpos($path, "/") + 1);
    $nodePath = substr($path, 0, strrpos($path, "/"));
    return $this->setNode($nodePath, $nodeName, $value, $overwrite);
  }
/**
 *
 * @param string $path full xPath including object name eg /form/others/myObject
 * @param unknown_type $object
 * @param unknown_type $overwrite
 */
  public function setObject($path, $object, $overwrite = true)
  { $obj = $this->setPath($path, $object, $overwrite);
    return $this->saveXML($obj);
    //return $this->setPath($path, $object, $overwrite);
  }

  public function setTableFromArr(array $array, $table_name = "__table__", array &$foreignKeys = null)
  { $table = self::createElement($table_name);
  	$this->tables->appendChild($table);
  	foreach($array as $rowKey => $row)
  	{ $XMLrow = self::createElement("row");
  	  $table->appendChild($XMLrow);
  	  foreach ($row as $key => $value)
  	  { if(!is_object($value) && !is_array($value) && !is_resource($value))
    		{ $field = self::createElement($key);
    	      $XMLrow->appendChild($field);
    	      if(isset($foreignKeys[$key]))
            { $XMLvalue = self::createTextNode(isset($foreignKeys[$key][$value]) ? $foreignKeys[$key][$value] : "*");
            } else
            { $XMLvalue = self::createTextNode($value);
            }
            $field->appendChild($XMLvalue);
    		}
  	  }
  	}
  	return $this->saveXML($table);
  }
}
